#ifndef _OBMP_TYPE_H_
#define _OBMP_TYPE_H_

#include <stddef.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdint.h>

typedef unsigned char           U8;
typedef unsigned short          U16;
typedef signed   short          S16;
typedef unsigned int            U32;
typedef signed int              S32;
typedef unsigned int            BIT_DEF;

#define SUPPORT_THREAD_MAX      ((sysconf(_SC_NPROCESSORS_CONF)) * 4)
/* Default slice size is 8, so the max unit memory size is 8*MAX_BLOCK_COUNT bytes */
#define MAX_BLOCK_COUNT         (sizeof(void *) * 8) /* 64bit -> 512bit bytes */
/* Each thread cache buffer size, should be aligned to PAGESIZE. default 1M */
#define PER_CACHE_SIZE          (1024 * 1024)

#define MAIN_AREA_SIZE          (PER_CACHE_SIZE)

#define __ALIGN_MASK(x, mask)   (((x) + (mask)) & ~(mask))
#define __ALIGN_MP(x, a)        __ALIGN_MASK(x, (a) - 1)

#define ALIGN(x, a)             __ALIGN_MP((x), (a))

#define SLICE_SIZE              (8)
#define SLICE_MASK              (SLICE_SIZE - 1)
#define SLICE_SHIFT             (3)

typedef struct st_mem_pool              mem_pool_t;
typedef struct st_mem_block_info        mem_block_info_t;
typedef struct st_thread_cache          thread_cache_t;

#define ptr_to_mem_unit(ptr) \
    (mem_unit_t *)(((uintptr_t)ptr) - sizeof(mem_unit_t))
#define mem_unit_to_ptr(unit_ptr) \
    (void *)(((uintptr_t)unit_ptr) + sizeof(mem_unit_t))

#if !defined(likely) && defined(__GNUC__)
    #define likely(x)      __builtin_expect(!!(x), 1)
    #define unlikely(x)    __builtin_expect(!!(x), 0)
#else
    #define likely(x)       (x)
    #define unlikely(x)     (x)
#endif

#ifndef MP_ASSERT
// # define MP_ASSERT(x)   if (!(x)) {abort();}
# define MP_ASSERT(x)
#endif

#define OBMP_UNUSED_VAR(x)      (void)(x)
#define OBMP_UNUSED_FUNC        __attribute__((__unused__))

// TODO: replace bit field
typedef union {
    struct {
        BIT_DEF     is_free            : 1;
        BIT_DEF     belongs            : 1;
        BIT_DEF     unit_size          : 30; /* Max support bytes small unit size */
    };
    U32             value;
} mem_unit_info_u;

typedef struct st_mem_unit {
    mem_unit_info_u info;
    U32             next; /* The offset based block address */
    void            *ptr;
} mem_unit_t __attribute__((aligned(sizeof(void *))));

struct st_mem_block_info {
    mem_unit_t      *mem_units;
};

struct st_thread_cache {
    U16             is_main_area;
    U16             block_cnt;
    struct st_chunk {
        void        *buffer;
        U32         buffer_size;
        U32         offset;
    } *chunk;
#ifdef OBMP_DEBUG
    pid_t           tid; /* For Debug */
#endif
    struct st_mem_block_info **big_blocks;
    struct st_mem_block_info **mem_blocks;
    pthread_mutex_t t_mutex;
};

struct st_mem_pool {
    U32             used_caches_cnt;
    U32             thread_cache_cnt;
    thread_cache_t  **thread_caches;
    pthread_mutex_t m_mutex;
};

#endif // endif _MP_TYPE_H_